package org.jflame.commons.config;

import org.jflame.commons.file.PropertiesHelper;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Properties;

/**
 * 默认实现 从properties文件加载配置参数.
 * <p>
 * 支持加密后属性值自动解密.
 * 
 * @author charles.zhang
 */
public class PropertiesConfig extends ConfigReader {

    private String[] propertiesFiles;
    private Properties properties;
    private EncryptedValueResolver encryptedValueResolver;

    /**
     * 构造函数,指定配置文件
     * 
     * @param propertiesFiles 配置文件路径
     * @throws IOException
     */
    public PropertiesConfig(String... propertiesFiles) throws IOException {
        Objects.requireNonNull(propertiesFiles, "propertiesFiles must not be null");
        this.propertiesFiles = propertiesFiles;
        loadFromProperties();

    }

    public PropertiesConfig(Properties properties) {
        this.properties = properties;
    }

    /**
     * 从属性配置文件加载参数
     * 
     * @throws IOException
     */
    protected void loadFromProperties() throws IOException {
        PropertiesHelper loader = new PropertiesHelper(propertiesFiles);
        if (loader != null) {
            properties = loader.getProperties();
        }

    }

    public void reload() throws IOException {
        clear();
        loadFromProperties();
    }

    /**
     * 设置参数
     * 
     * @param paramKey 参数名
     * @param value 参数值
     */
    public void addParam(Object paramKey, Object value) {
        properties.put(paramKey, value);
    }

    /**
     * 设置多个参数
     * 
     * @param m 参数map
     */
    public void addParams(Map<? extends Object,? extends Object> m) {
        properties.putAll(m);
    }

    /**
     * 返回所有属性和值的map
     * 
     * @return
     */
    public Map<String,Object> getParams() {
        Map<String,Object> paramMap = new HashMap<>(properties.size());
        for (Entry<Object,Object> kv : properties.entrySet()) {
            paramMap.put(kv.getKey()
                    .toString(), kv.getValue());
        }
        return paramMap;
    }

    /**
     * 返回特定前缀的所有属性
     * 
     * @param prefix 键前缀
     * @return Properties,不存在返回null
     */
    public Properties filterByPrefix(final String prefix) {
        if (properties == null) {
            return null;
        }
        Properties propertiesPart = new Properties();
        properties.forEach((k, v) -> {
            if (k.toString()
                    .startsWith(prefix)) {
                propertiesPart.put(k, v);
            }
        });
        return propertiesPart.isEmpty() ? null : propertiesPart;
    }

    public void clear() {
        if (properties != null) {
            properties.clear();
        }
    }

    public void setPropertiesFiles(String[] propertiesFiles) {
        this.propertiesFiles = propertiesFiles;
    }

    public Properties getProperties() {
        return properties;
    }

    @Override
    public boolean hasKey(String key) {
        if (properties != null) {
            return properties.containsKey(key);
        }
        return false;
    }

    /**
     * 判断是否存在以参数keyPrefix开头的属性
     * 
     * @param keyPrefix
     * @return
     */
    public boolean hasAnyKeyPrefix(final String keyPrefix) {
        if (properties == null) {
            return false;
        }
        return properties.stringPropertyNames()
                .stream()
                .anyMatch(k -> k.startsWith(keyPrefix));
    }

    @Override
    public String getValue(String configKey) {
        return properties != null ? properties.getProperty(configKey) : null;
    }

    /**
     * 启用加密值解析支持,默认使用PBEWithMD5AndDES解析
     * 
     * @param password 密钥
     */
    public void enableEncryptedValueResolver(String password) {
        encryptedValueResolver = EncryptedValueResolver.buildByPBE(password);
    }

    public void setEncryptedValueResolver(EncryptedValueResolver _encryptedValueResolver) {
        encryptedValueResolver = _encryptedValueResolver;
    }

    @Override
    public EncryptedValueResolver getEncryptedValueResolver() {
        return encryptedValueResolver;
    }

}
